package com.gusto.engine.recommend.delagate.impl;

import java.util.List;

import com.gusto.engine.colfil.Distance;
import com.gusto.engine.recommend.delagate.ColNeighborhoodDelegate;
import com.gusto.engine.recommend.delagate.NeighborhoodDelegate;
import com.gusto.engine.recommend.delagate.SemNeighborhoodDelegate;
import com.opensymphony.oscache.base.Cache;

/**
 * <p>Cached neighborhood delegate implementation.
 * Needs the cached {@link NeighborhoodDelegate} to be injected.</p>
 * 
 * @author amokrane.belloui@gmail.com
 *
 */
public class NeighborhoodDelegateCachedImpl implements NeighborhoodDelegate, ColNeighborhoodDelegate, SemNeighborhoodDelegate {
	
	private Cache cache = null;
	public void setCache(Cache cache) {
		this.cache = cache;
		//preloadCache();
	}
	
	private NeighborhoodDelegate neighborhoodDelegate;
	public void setNeighborhoodDelegate(NeighborhoodDelegate neighborhoodDelegate) {
		this.neighborhoodDelegate = neighborhoodDelegate;
	}
	
	@SuppressWarnings("unchecked")
	public List<Distance> getNearItems(long itemId, String formula, int MIN_SHARED_ITEM, Integer MAX_NEIGHBORS, double MIN_SIMILARITY) throws Exception {
		if (!(neighborhoodDelegate instanceof ColNeighborhoodDelegate)) {
			throw new Exception("Not a Collaborative DAO");
		}
		ColNeighborhoodDelegate cnd = (ColNeighborhoodDelegate)neighborhoodDelegate;
		
		List<Distance> items;
		String key = "item.neighborhood.collab.items." + itemId;
		try {
			items = (List<Distance>) cache.getFromCache(key);
		} 
		catch (com.opensymphony.oscache.base.NeedsRefreshException nre) {
		    try {
		    	items = cnd.getNearItems(itemId, formula, MIN_SHARED_ITEM, MAX_NEIGHBORS, MIN_SIMILARITY);
		        cache.putInCache(key, items);
		    } 
		    catch (Exception ex) {
		    	items = (List<Distance>) nre.getCacheContent();
		        cache.cancelUpdate(key);
		    }
		}
	    return items;
	}
	
	@SuppressWarnings("unchecked")
	public List<Distance> getNearUsers(long userId, String formula, int MIN_SHARED_ITEM, Integer MAX_NEIGHBORS, double MIN_SIMILARITY) throws Exception {
		if (!(neighborhoodDelegate instanceof ColNeighborhoodDelegate)) {
			throw new Exception("Not a Collaborative DAO");
		}
		ColNeighborhoodDelegate cnd = (ColNeighborhoodDelegate)neighborhoodDelegate;
		
		List<Distance> users;
		String key = "user.neighborhood.collab.users." + userId;
		try {
			users = (List<Distance>) cache.getFromCache(key);
		} 
		catch (com.opensymphony.oscache.base.NeedsRefreshException nre) {
		    try {
		    	users = cnd.getNearUsers(userId, formula, MIN_SHARED_ITEM, MAX_NEIGHBORS, MIN_SIMILARITY);
		        cache.putInCache(key, users);
		    } 
		    catch (Exception ex) {
		    	users = (List<Distance>) nre.getCacheContent();
		        cache.cancelUpdate(key);
		    }
		}
		return users;
	}
	
	@SuppressWarnings("unchecked")
	public List<Distance> getNearItems(long itemId, Integer MAX_NEIGHBORS, Double MIN_SIMILARITY) throws Exception {
		if (!(neighborhoodDelegate instanceof SemNeighborhoodDelegate)) {
			throw new Exception("Not a Semantic DAO");
		}
		SemNeighborhoodDelegate snd = (SemNeighborhoodDelegate)neighborhoodDelegate;
		
		List<Distance> items;
		String key = "item.neighborhood.sem.items." + itemId;
		try {
			items = (List<Distance>) cache.getFromCache(key);
		} 
		catch (com.opensymphony.oscache.base.NeedsRefreshException nre) {
		    try {
		    	items = snd.getNearItems(itemId, MAX_NEIGHBORS, MIN_SIMILARITY);
		        cache.putInCache(key, items);
		    } 
		    catch (Exception ex) {
		    	items = (List<Distance>) nre.getCacheContent();
		        cache.cancelUpdate(key);
		    }
		}
	    return items;
	}
	
	@SuppressWarnings("unchecked")
	public List<Distance> getNearUsers(long userId, Integer MAX_NEIGHBORS, Double MIN_SIMILARITY) throws Exception {
		if (!(neighborhoodDelegate instanceof SemNeighborhoodDelegate)) {
			throw new Exception("Not a Semantic DAO");
		}
		SemNeighborhoodDelegate snd = (SemNeighborhoodDelegate)neighborhoodDelegate;
		
		List<Distance> users;
		String key = "user.neighborhood.sem.users." + userId;
		try {
			users = (List<Distance>) cache.getFromCache(key);
		} 
		catch (com.opensymphony.oscache.base.NeedsRefreshException nre) {
		    try {
		    	users = snd.getNearUsers(userId, MAX_NEIGHBORS, MIN_SIMILARITY);
		        cache.putInCache(key, users);
		    } 
		    catch (Exception ex) {
		    	users = (List<Distance>) nre.getCacheContent();
		        cache.cancelUpdate(key);
		    }
		}
		return users;
	}
	
}
